package com.shanks.framework.mq.common.util;

import com.shanks.framework.mq.domain.MQMessage;
import com.shanks.framework.mq.exception.MQException;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.*;

import static com.shanks.framework.mq.common.constant.MQConstant.MSG.*;

public class MQUtil {

    private static byte[] messageSignaturePrefix;

    public static List<String> mQProducerKeys = new ArrayList<>();

    static {
        try {
            messageSignaturePrefix = "SHANKS_1433223_".getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
        }
    }

    public static String createSignature(String topic, String tags, String key, byte[] body, String source) throws MQException {
        Map<String, Object> messageData = new HashMap<>();
        messageData.put(MSG_TOPIC, topic);
        messageData.put(MSG_TAG, tags);
        messageData.put(MSG_KEY, key);
        messageData.put(MSG_BODY, body);
        messageData.put(MSG_SOURCE, source);
        return createSignature(messageData);
    }

    /**
     * 计算消息内容签名
     *
     * @param messageData
     * @return
     * @throws MQException
     */
    public static String createSignature(Map<String, Object> messageData) throws MQException {
        //对key进行排序，避免验证签名数据时不一致
        List<String> keys = new ArrayList<>(messageData.keySet());
        Collections.sort(keys);
        try {
            MessageDigest msgDigest = MessageDigest.getInstance("MD5");
            msgDigest.update(messageSignaturePrefix);

            for (String key : keys) {
                Object value = messageData.get(key);
                if (value == null) {
                    continue;
                }
                //排除签名属性本身
                if (!PROPERTY_SIGNATURE.equals(key)) {
                    if (value instanceof byte[]) {
                        msgDigest.update((byte[]) value);
                    } else {
                        msgDigest.update(value.toString().getBytes("UTF-8"));
                    }
                }
            }

            byte[] bytes = msgDigest.digest();
            return new String(MD5Util.encodeHex(bytes));
        } catch (Exception e) {
            throw new MQException("计算消息签名失败", e);
        }
    }

    /**
     * 根据原始topic和tag生成ack消息的tag
     *
     * @param originTopic
     * @param originTag
     * @return
     */
    public static String getAckMsgTag(String originTopic, String originTag) {
        originTopic = StringUtils.trimToNull(originTopic);
        originTag = StringUtils.trimToNull(originTag);
        if (StringUtils.isBlank(originTopic)) {
            throw new IllegalArgumentException("原始消息topic不能为空");
        }
        if (StringUtils.isBlank(originTag)) {
            throw new IllegalArgumentException("原始消息tag不能为空");
        }
        //分解原始tags，生成ack tags
        String[] tags = StringUtils.split(originTag, "||");
        Set<String> ackTags = new HashSet<>();
        for (String tag : tags) {
            tag = tag.trim();
            if ("*".equals(tag)) {
                ackTags.add(originTopic);
            } else {
                ackTags.add(originTopic + "_" + tag);
            }
        }
        return StringUtils.join(ackTags, " || ");
    }

    public static String getCheckCode(MQMessage message) {
        try {
            MessageDigest msgDigest = MessageDigest.getInstance("MD5");
            msgDigest.update(message.getBody());
            return message.getTopic() + "_" + message.getTopic();
        } catch (Exception e) {
            throw new RuntimeException("计算消息校验码失败", e);
        }
    }

    /**
     * 生成消息uuid
     *
     * @param messageTopic
     * @param messageJson
     * @return
     */
    public static String generateMessageUuid(String messageTopic, String messageJson) {
        // topic + json md5 放重复
        try {
            MessageDigest msgDigest = MessageDigest.getInstance("MD5");
            msgDigest.update(messageTopic.getBytes("UTF-8"));
            msgDigest.update(messageJson.getBytes("UTF-8"));
            byte[] bytes = msgDigest.digest();
            return new String(MD5Util.encodeHex(bytes));
        } catch (Exception e) {
            throw new RuntimeException("计算消息messageUuid失败", e);
        }

    }
}
